package edu.ntu.cloudroid.xacml.builder.policy;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.sun.xacml.Obligation;
import com.sun.xacml.UnknownIdentifierException;
import com.sun.xacml.attr.IntegerAttribute;
import com.sun.xacml.attr.StringAttribute;
import com.sun.xacml.attr.TimeAttribute;
import com.sun.xacml.cond.Apply;
import com.sun.xacml.cond.EqualFunction;
import com.sun.xacml.cond.Evaluatable;
import com.sun.xacml.cond.Function;
import com.sun.xacml.cond.FunctionFactory;
import com.sun.xacml.cond.FunctionTypeException;
import com.sun.xacml.cond.LogicalFunction;
import com.sun.xacml.ctx.Attribute;
import com.sun.xacml.ctx.Result;

import edu.ntu.cloudroid.model.IDs;
import edu.ntu.cloudroid.model.friend.GroupData;
import edu.ntu.cloudroid.model.policy.AbstractPrivacyPreference;
import edu.ntu.cloudroid.model.policy.SimpleFiltering;
import edu.ntu.cloudroid.model.profile.ProfileData;
import edu.ntu.cloudroid.xacml.XACMLStrings;

/**
 * Extending the AbstractPolicyBuilder to define the condition rules used for
 * generating the policy
 * 
 */
public class SimpleFilteringBuilder extends AbstractPolicyBuilder {
	
	SimpleFiltering sfpp;
			
	@Override
	//if there's time constrained, added to the rule here
	public List<Apply> createRuleConditions(
			AbstractPrivacyPreference pref, List<Apply> andedFunctions,
			FunctionFactory factory) throws Exception{
		sfpp = (SimpleFiltering) this.preference;
		if (sfpp.getConstraintType() == SimpleFiltering.TIMECONSTRAINT) {
			andedFunctions = this.createRuleForTimeConstraint(sfpp, andedFunctions,
					factory);
		}
		return andedFunctions;
	}
	
	private List<Apply> createRuleForTimeConstraint(
			SimpleFiltering sfpp, List<Apply> andedFunctions,
			FunctionFactory factory) throws Exception {
		Function function = factory
				.createFunction(XACMLStrings.FN_SubjectInTimeBoundsOfResource);
		List<Evaluatable> functionArgs = new ArrayList<Evaluatable>();
		functionArgs.add(new TimeAttribute(sfpp.getLowerTime(), 0, 0, 0));
		functionArgs.add(new TimeAttribute(sfpp.getUpperTime(), 0, 0, 0));
		Apply applyIsWithinTimeZone = new Apply(function, functionArgs, false);
		andedFunctions.add(applyIsWithinTimeZone);		
		return andedFunctions;
	}

	@Override
	protected Set<Obligation> createObligations() throws Exception{		
		//if filtering based on time constraint, skipped
		if (this.sfpp.getConstraintType()== SimpleFiltering.TIMECONSTRAINT)
			return null;
		
		List<Attribute> atts = new ArrayList<Attribute>();
		atts.add(new Attribute(new URI(XACMLStrings.ATTR_Filtering_ColumnIdx), null,
				null, new IntegerAttribute(sfpp.getDataColumnIndex())));
		atts.add(new Attribute(new URI(XACMLStrings.ATTR_Filtering_Cond), null,
				null, new IntegerAttribute(sfpp.getConditionType())));
		atts.add(new Attribute(new URI(XACMLStrings.ATTR_Filtering_Val), null,
				null, new StringAttribute(sfpp.getConstraintValue())));
		
		Obligation filteringObligation = new Obligation(new URI(
				IDs.ObligationID.FilteringObligation.toString()),
				Result.DECISION_PERMIT, atts);		
		Set<Obligation> obs = new HashSet<Obligation>();
		obs.add(filteringObligation);
		return obs;
	}
}
